package com.ruoyi.project.file.common.service;

/**
 * @author zhangqidi
 * @date 2025/8/6
 * @description TODO
 **/

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.lang.Dict;
import cn.hutool.core.util.StrUtil;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.ruoyi.common.utils.UUIDUtils;
import com.ruoyi.project.file.detail.domain.FileDetail;
import com.ruoyi.project.file.detail.mapper.FileDetailMapper;
import com.ruoyi.project.system.user.service.UserServiceImpl;
import org.dromara.x.file.storage.core.FileInfo;
import org.dromara.x.file.storage.core.hash.HashInfo;
import org.dromara.x.file.storage.core.recorder.FileRecorder;
import org.dromara.x.file.storage.core.upload.FilePartInfo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.Map;

/**
 * 用来将文件上传记录保存到数据库，这里使用了 MyBatis-Plus 和 Hutool 工具类
 */
@Service
public class FileService implements FileRecorder {
    private static final Logger log = LoggerFactory.getLogger(UserServiceImpl.class);
    private final ObjectMapper objectMapper = new ObjectMapper();

    @Autowired
    private FileDetailMapper fileDetailMapper;

    /**
     * 保存文件信息到数据库
     */
//    @SneakyThrows
    @Override
    public boolean save(FileInfo info){
        try{
            // 生成id
            if (info.getId() == null) {
                info.setId(UUIDUtils.random32UUID());
            }
            FileDetail detail = toFileDetail(info);
            int b = fileDetailMapper.insertFileDetail(detail);
            if (b == 1) {
                info.setId(detail.getId());
                return true;
            } else {
                return false;
            }
        }catch (JsonProcessingException e){
            log.error("文件保存失败", e);
            return false;
        }
    }

    /**
     * 更新文件记录，可以根据文件 ID 或 URL 来更新文件记录，
     * 主要用在手动分片上传文件-完成上传，作用是更新文件信息
     */
//    @SneakyThrows
    @Override
    public void update(FileInfo info) {
        try{
            FileDetail detail = toFileDetail(info);
            fileDetailMapper.updateFileDetail(detail);
        }catch (JsonProcessingException e){
            log.error("文件更新失败", e);
        }
    }

    /**
     * 根据 url 查询文件信息
     */
//    @SneakyThrows
    @Override
    public FileInfo getByUrl(String url) {
        try {
            FileDetail detail = fileDetailMapper.selectFileDetailByUrl(url);
            return toFileInfo(detail);
        }catch (JsonProcessingException e){
            log.error("文件根据url查询失败", e);
            return null;
        }
    }

    /**
     * 根据 url 删除文件信息
     */
    @Override
    public boolean delete(String url) {
        int b = fileDetailMapper.deleteFileDetailByUrl(url);
        if (b == 1) {
            return true;
        } else {
            return false;
        }
    }

    @Override
    public void saveFilePart(FilePartInfo filePartInfo) {
    }

    @Override
    public void deleteFilePartByUploadId(String id) {
    }

    /**
     * 将 FileInfo 转为 FileDetail
     */
    public FileDetail toFileDetail(FileInfo info) throws JsonProcessingException {
        FileDetail detail = BeanUtil.copyProperties(
                info, FileDetail.class, "metadata", "userMetadata", "thMetadata", "thUserMetadata", "attr", "hashInfo");

        // 这里手动获 元数据 并转成 json 字符串，方便存储在数据库中
        detail.setMetadata(valueToJson(info.getMetadata()));
        detail.setUserMetadata(valueToJson(info.getUserMetadata()));
        detail.setThMetadata(valueToJson(info.getThMetadata()));
        detail.setThUserMetadata(valueToJson(info.getThUserMetadata()));
        // 这里手动获 取附加属性字典 并转成 json 字符串，方便存储在数据库中
        detail.setAttr(valueToJson(info.getAttr()));
        // 这里手动获 哈希信息 并转成 json 字符串，方便存储在数据库中
        detail.setHashInfo(valueToJson(info.getHashInfo()));
        return detail;
    }

    /**
     * 将 FileDetail 转为 FileInfo
     */
    public FileInfo toFileInfo(FileDetail detail) throws JsonProcessingException {
        FileInfo info = BeanUtil.copyProperties(
                detail, FileInfo.class, "metadata", "userMetadata", "thMetadata", "thUserMetadata", "attr", "hashInfo");

        // 这里手动获取数据库中的 json 字符串 并转成 元数据，方便使用
        info.setMetadata(jsonToMetadata(detail.getMetadata()));
        info.setUserMetadata(jsonToMetadata(detail.getUserMetadata()));
        info.setThMetadata(jsonToMetadata(detail.getThMetadata()));
        info.setThUserMetadata(jsonToMetadata(detail.getThUserMetadata()));
        // 这里手动获取数据库中的 json 字符串 并转成 附加属性字典，方便使用
        info.setAttr(jsonToDict(detail.getAttr()));
        // 这里手动获取数据库中的 json 字符串 并转成 哈希信息，方便使用
        info.setHashInfo(jsonToHashInfo(detail.getHashInfo()));
        return info;
    }

    /**
     * 将指定值转换成 json 字符串
     */
    public String valueToJson(Object value) throws JsonProcessingException {
        if (value == null){
            return null;
        }
        return objectMapper.writeValueAsString(value);
    }

    /**
     * 将 json 字符串转换成元数据对象
     */
    public Map<String, String> jsonToMetadata(String json) throws JsonProcessingException {
        if (StrUtil.isBlank(json)){
            return null;
        }
        return objectMapper.readValue(json, new TypeReference<Map<String, String>>() {});
    }

    /**
     * 将 json 字符串转换成字典对象
     */
    public Dict jsonToDict(String json) throws JsonProcessingException {
        if (StrUtil.isBlank(json)){
            return null;
        }
        return objectMapper.readValue(json, Dict.class);
    }

    /**
     * 将 json 字符串转换成哈希信息对象
     */
    public HashInfo jsonToHashInfo(String json) throws JsonProcessingException {
        if (StrUtil.isBlank(json)){
            return null;
        }
        return objectMapper.readValue(json, HashInfo.class);
    }
}
